home *** CD-ROM | disk | FTP | other *** search
- From: genrad!decvax!minow (Martin Minow)
- Subject: MicroEmacs (Part 2 of 6)
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 4, Issue 69
- Submitted by: decvax!minow (Martin Minow)
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # echo.c
- # extend.c
- # file.c
- # kbd.c
- # line.c
- # main.c
- # This archive created: Sun Apr 13 11:15:48 1986
- export PATH; PATH=/bin:$PATH
- echo shar: extracting "'echo.c'" '(8844 characters)'
- if test -f 'echo.c'
- then
- echo shar: will not over-write existing file "'echo.c'"
- else
- cat << \SHAR_EOF > 'echo.c'
- /*
- * Name: MicroEMACS
- * Echo line reading and writing.
- * Version: 29
- * Last edit: 14-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- *
- * Common routines for reading
- * and writing characters in the echo line area
- * of the display screen. Used by the entire
- * known universe.
- */
- #include "def.h"
-
- int epresf = FALSE; /* Stuff in echo line flag. */
- int nmsg = 0; /* Size of occupied msg. area. */
- int curmsgf = FALSE; /* Current alert state. */
- int newmsgf = FALSE; /* New alert state. */
-
- char msg[NMSG]; /* Random message storage. */
-
- /*
- * Send a string to the message system.
- * Add a free newline to the end of the message string.
- * Return TRUE if it fits, and FALSE if it does not.
- * Perhaps the message buffer should know how to get
- * larger, just like the kill buffer?
- */
- writemsg(sp)
- register char *sp;
- {
- register int c;
-
- if (nmsg+strlen(sp)+1 > NMSG) /* "+1" for the "\n". */
- return (FALSE);
- while ((c = *sp++) != '\0')
- msg[nmsg++] = c;
- msg[nmsg++] = '\n';
- newmsgf = TRUE; /* Update mode line. */
- return (TRUE);
- }
-
- /*
- * Read messages. The message lines are
- * displayed, one line at a time, in the message line.
- * A special sub-mode is entered, in which the keys have
- * the following meanings:
- * ^P Go backward 1 line.
- * BS Go backward 1 line.
- * ^N Go forward 1 line. Quit if at the end.
- * SP Go forward 1 line. Quit if at the end.
- * CR Go forward 1 line. Quit if at the end.
- * ^G Abort, leave old text.
- * ^C Quit, delete anything already read.
- * Return TRUE if you left this mode in a reasonable
- * way (not ^G), and ABORT if you quit the mode with a
- * ^G.
- */
- readmsg()
- {
- register int c;
- register int i;
- register int j;
-
- if (nmsg == 0) /* Duck out if none. */
- return (TRUE);
- newmsgf = FALSE; /* Kill alert, and do */
- update(); /* a redisplay. */
- ttcolor(CTEXT);
- i = 0;
- while (i < nmsg) {
- ttmove(nrow-1, 0); /* Display 1 line. */
- while (i<nmsg && (c=msg[i++])!='\n')
- eputc(c);
- tteeol();
- ttmove(nrow-1, 0); /* Looks nice. */
- ttflush();
- for (;;) { /* Editing loop. */
- c = ttgetc();
- switch (c) {
- case 0x0E: /* ^N */
- case 0x20: /* SP */
- case 0x0D: /* CR */
- break;
-
- case 0x10: /* ^P */
- case 0x08: /* BS */
- do {
- --i;
- } while (i!=0 && msg[i-1]!='\n');
- if (i != 0) {
- do { /* Back up 1 line. */
- --i;
- } while (i!=0 && msg[i-1]!='\n');
- }
- break;
-
- case 0x03: /* ^C */
- j = 0; /* Eat what we read. */
- while (i < nmsg)
- msg[j++] = msg[i++];
- nmsg = j;
- eerase();
- return (TRUE);
-
- case 0x07: /* ^G */
- ttbeep();
- eerase();
- return (ABORT);
-
- default: /* Loop on the rest. */
- continue;
- }
- break;
- }
- }
- nmsg = 0; /* Flow off the end. */
- eerase();
- return (TRUE);
- }
-
- /*
- * Erase the echo line.
- */
- eerase()
- {
- ttcolor(CTEXT);
- ttmove(nrow-1, 0);
- tteeol();
- ttflush();
- epresf = FALSE;
- }
-
- /*
- * Ask "yes" or "no" question.
- * Return ABORT if the user answers the question
- * with the abort ("^G") character. Return FALSE
- * for "no" and TRUE for "yes". No formatting
- * services are available.
- */
- eyesno(sp)
- char *sp;
- {
- register int s;
- char buf[64];
-
- for (;;) {
- s = ereply("%s [y/n]? ", buf, sizeof(buf), sp);
- if (s == ABORT)
- return (ABORT);
- if (s != FALSE) {
- if (buf[0]=='y' || buf[0]=='Y')
- return (TRUE);
- if (buf[0]=='n' || buf[0]=='N')
- return (FALSE);
- }
- }
- }
-
- /*
- * Write out a prompt, and read back a
- * reply. The prompt is now written out with full "eprintf"
- * formatting, although the arguments are in a rather strange
- * place. This is always a new message, there is no auto
- * completion, and the return is echoed as such.
- */
- /* VARARGS3 */
- ereply(fp, buf, nbuf, arg)
- char *fp;
- char *buf;
- {
- return (eread(fp, buf, nbuf, EFNEW|EFCR, (char *)&arg));
- }
-
- /*
- * This is the general "read input from the
- * echo line" routine. The basic idea is that the prompt
- * string "prompt" is written to the echo line, and a one
- * line reply is read back into the supplied "buf" (with
- * maximum length "len"). The "flag" contains EFNEW (a
- * new prompt), an EFAUTO (autocomplete), or EFCR (echo
- * the carriage return as CR).
- */
- eread(fp, buf, nbuf, flag, ap)
- char *fp;
- char *buf;
- char *ap;
- {
- register int cpos;
- register SYMBOL *sp1;
- register SYMBOL *sp2;
- register int i;
- register int c;
- register int h;
- register int nhits;
- register int nxtra;
- register int bxtra;
-
- cpos = 0;
- if (kbdmop != NULL) { /* In a macro. */
- while ((c = *kbdmop++) != '\0')
- buf[cpos++] = c;
- buf[cpos] = '\0';
- goto done;
- }
- if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
- ttcolor(CTEXT);
- ttmove(nrow-1, 0);
- epresf = TRUE;
- } else
- eputc(' ');
- eformat(fp, ap);
- tteeol();
- ttflush();
- for (;;) {
- c = ttgetc();
- if (c==' ' && (flag&EFAUTO)!=0) {
- nhits = 0;
- nxtra = HUGE;
- for (h=0; h<NSHASH; ++h) {
- sp1 = symbol[h];
- while (sp1 != NULL) {
- for (i=0; i<cpos; ++i) {
- if (buf[i] != sp1->s_name[i])
- break;
- }
- if (i == cpos) {
- if (nhits == 0)
- sp2 = sp1;
- ++nhits;
- bxtra = getxtra(sp1, sp2, cpos);
- if (bxtra < nxtra)
- nxtra = bxtra;
- }
- sp1 = sp1->s_symp;
- }
- }
- if (nhits == 0) /* No completion. */
- continue;
- for (i=0; i<nxtra && cpos<nbuf-1; ++i) {
- c = sp2->s_name[cpos];
- buf[cpos++] = c;
- eputc(c);
- }
- ttflush();
- if (nhits != 1) /* Fake a CR if there */
- continue; /* is 1 choice. */
- c = 0x0D;
- }
- switch (c) {
- case 0x0D: /* Return, done. */
- buf[cpos] = '\0';
- if (kbdmip != NULL) {
- if (kbdmip+cpos+1 > &kbdm[NKBDM-3]) {
- (void) ctrlg(FALSE, 0, KRANDOM);
- ttflush();
- return (ABORT);
- }
- for (i=0; i<cpos; ++i)
- *kbdmip++ = buf[i];
- *kbdmip++ = '\0';
- }
- if ((flag&EFCR) != 0) {
- ttputc(0x0D);
- ttflush();
- }
- goto done;
-
- case 0x07: /* Bell, abort. */
- eputc(0x07);
- (void) ctrlg(FALSE, 0, KRANDOM);
- ttflush();
- return (ABORT);
-
- case 0x7F: /* Rubout, erase. */
- case 0x08: /* Backspace, erase. */
- if (cpos != 0) {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- if (ISCTRL(buf[--cpos]) != FALSE) {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- }
- ttflush();
- }
- break;
-
- case 0x15: /* C-U, kill line. */
- while (cpos != 0) {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- if (ISCTRL(buf[--cpos]) != FALSE) {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- }
- }
- ttflush();
- break;
-
- default: /* All the rest. */
- if (cpos < nbuf-1) {
- buf[cpos++] = c;
- eputc(c);
- ttflush();
- }
- }
- }
- done:
- if (buf[0] == '\0')
- return (FALSE);
- return (TRUE);
- }
-
- /*
- * The "sp1" and "sp2" point to extended command
- * symbol table entries. The "cpos" is a horizontal position
- * in the name. Return the longest block of characters that can
- * be autocompleted at this point. Sometimes the two symbols
- * are the same, but this is normal.
- */
- getxtra(sp1, sp2, cpos)
- register SYMBOL *sp1;
- register SYMBOL *sp2;
- {
- register int i;
-
- i = cpos;
- for (;;) {
- if (sp1->s_name[i] != sp2->s_name[i])
- break;
- if (sp1->s_name[i] == '\0')
- break;
- ++i;
- }
- return (i - cpos);
- }
-
- /*
- * Special "printf" for the echo line.
- * Each call to "eprintf" starts a new line in the
- * echo area, and ends with an erase to end of the
- * echo line. The formatting is done by a call
- * to the standard formatting routine.
- */
- /* VARARGS1 */
- eprintf(fp, arg)
- char *fp;
- {
- ttcolor(CTEXT);
- ttmove(nrow-1, 0);
- eformat(fp, (char *)&arg);
- tteeol();
- ttflush();
- epresf = TRUE;
- }
-
- /*
- * Printf style formatting. This is
- * called by both "eprintf" and "ereply", to provide
- * formatting services to their clients. The move to the
- * start of the echo line, and the erase to the end of
- * the echo line, is done by the caller.
- */
- eformat(fp, ap)
- register char *fp;
- register char *ap;
- {
- register int c;
-
- while ((c = *fp++) != '\0') {
- if (c != '%')
- eputc(c);
- else {
- c = *fp++;
- switch (c) {
- case 'd':
- eputi(*(int *)ap, 10);
- ap += sizeof(int);
- break;
-
- case 'o':
- eputi(*(int *)ap, 8);
- ap += sizeof(int);
- break;
-
- case 's':
- eputs(*(char **)ap);
- ap += sizeof(char *);
- break;
-
- default:
- eputc(c);
- }
- }
- }
- }
-
- /*
- * Put integer, in radix "r".
- */
- eputi(i, r)
- register int i;
- register int r;
- {
- register int q;
-
- if ((q=i/r) != 0)
- eputi(q, r);
- eputc(i%r+'0');
- }
-
- /*
- * Put string.
- */
- eputs(s)
- register char *s;
- {
- register int c;
-
- while ((c = *s++) != '\0')
- eputc(c);
- }
-
- /*
- * Put character. Watch for
- * control characters, and for the line
- * getting too long.
- */
- eputc(c)
- register int c;
- {
- if (ttcol < ncol) {
- if (ISCTRL(c) != FALSE) {
- eputc('^');
- c ^= 0x40;
- }
- ttputc(c);
- ++ttcol;
- }
- }
- SHAR_EOF
- if test 8844 -ne "`wc -c < 'echo.c'`"
- then
- echo shar: error transmitting "'echo.c'" '(should have been 8844 characters)'
- fi
- fi
- echo shar: extracting "'extend.c'" '(3416 characters)'
- if test -f 'extend.c'
- then
- echo shar: will not over-write existing file "'extend.c'"
- else
- cat << \SHAR_EOF > 'extend.c'
- /*
- * Name: MicroEMACS
- * Extended (M-X) commands.
- * Version: 29
- * Last edit: 14-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- */
- #include "def.h"
-
- /*
- * This function modifies the keyboard
- * binding table, by adjusting the entries in the
- * big "bindings" array. Most of the grief deals with the
- * prompting for additional arguments. This code does not
- * work right if there is a keyboard macro floating around.
- * Should be fixed.
- */
- bindtokey(f, n, k)
- {
- register int s;
- register char *cp;
- register SYMBOL *sp;
- register int c;
- char xname[NXNAME];
-
- if (kbdmip!=NULL || kbdmop!=NULL) {
- eprintf("Not now");
- return (FALSE);
- }
- if ((s=eread("Function: ", xname, NXNAME, EFAUTO, NULL)) != TRUE)
- return (s);
- if ((sp=symlookup(xname)) == NULL) {
- eprintf("Unknown function for binding");
- return (FALSE);
- }
- eputc(' ');
- eputc('K');
- eputc('e');
- eputc('y');
- eputc(':');
- eputc(' ');
- ttflush();
- c = getkey(); /* Read key. */
- keyname(xname, c); /* Display keyname. */
- eputs(xname);
- ttflush();
- if (binding[c] != NULL) /* Unbind old, and */
- --binding[c]->s_nkey;
- binding[c] = sp; /* rebind new. */
- ++sp->s_nkey;
- return (TRUE);
- }
-
- /*
- * Extended command. Call the message line
- * routine to read in the command name and apply autocompletion
- * to it. When it comes back, look the name up in the symbol table
- * and run the command if it is found and has the right type.
- * Print an error if there is anything wrong.
- */
- extend(f, n, k)
- {
- register SYMBOL *sp;
- register int s;
- char xname[NXNAME];
-
- if ((s=eread(": ", xname, NXNAME, EFNEW|EFAUTO, NULL)) != TRUE)
- return (s);
- if ((sp=symlookup(xname)) != NULL)
- return ((*sp->s_funcp)(f, n, KRANDOM));
- eprintf("Unknown extended command");
- return (ABORT);
- }
-
- /*
- * Read a key from the keyboard, and look it
- * up in the binding table. Display the name of the function
- * currently bound to the key. Say that the key is not bound
- * if it is indeed not bound, or if the type is not a
- * "builtin". This is a bit of overkill, because this is the
- * only kind of function there is.
- */
- help(f, n, k)
- {
- register SYMBOL *sp;
- register int c;
- char b[20];
-
- c = getkey();
- keyname(b, c);
- if ((sp=binding[c]) == NULL)
- eprintf("[%s is unbound]", b);
- else
- eprintf("[%s is bound to %s]", b, sp->s_name);
- return (TRUE);
- }
-
- /*
- * This function creates a table, listing all
- * of the command keys and their current bindings, and stores
- * the table in the standard pop-op buffer (the one used by the
- * directory list command, the buffer list command, etc.). This
- * lets MicroEMACS produce it's own wall chart. The bindings to
- * "ins-self" are only displayed if there is an argument.
- */
- wallchart(f, n, k)
- {
- register int s;
- register int key;
- register SYMBOL *sp;
- register char *cp1;
- register char *cp2;
- char buf[64];
-
- if ((s=bclear(blistp)) != TRUE) /* Clear it out. */
- return (s);
- (void) strcpy(blistp->b_fname, "");
- for (key=0; key<NKEYS; ++key) { /* For all keys. */
- sp = binding[key];
- if (sp != NULL
- && (f!=FALSE || strcmp(sp->s_name, "ins-self")!=0)) {
- keyname(buf, key);
- cp1 = &buf[0]; /* Find end. */
- while (*cp1 != 0)
- ++cp1;
- while (cp1 < &buf[16]) /* Goto column 16. */
- *cp1++ = ' ';
- cp2 = sp->s_name; /* Add function name. */
- while (*cp1++ = *cp2++)
- ;
- if (addline(buf) == FALSE)
- return (FALSE);
- }
- }
- return (popblist());
- }
- SHAR_EOF
- if test 3416 -ne "`wc -c < 'extend.c'`"
- then
- echo shar: error transmitting "'extend.c'" '(should have been 3416 characters)'
- fi
- fi
- echo shar: extracting "'file.c'" '(9404 characters)'
- if test -f 'file.c'
- then
- echo shar: will not over-write existing file "'file.c'"
- else
- cat << \SHAR_EOF > 'file.c'
- /*
- * Name: MicroEMACS
- * File commands.
- * Version: 29
- * Last edit: 05-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- */
- #include "def.h"
-
- /*
- * Read a file into the current
- * buffer. This is really easy; all you do it
- * find the name of the file, and call the standard
- * "read a file into the current buffer" code.
- */
- fileread(f, n, k)
- {
- register int s;
- char fname[NFILEN];
-
- if ((s=ereply("Read file: ", fname, NFILEN)) != TRUE)
- return (s);
- adjustcase(fname);
- return (readin(fname));
- }
-
- /*
- * Select a file for editing.
- * Look around to see if you can find the
- * fine in another buffer; if you can find it
- * just switch to the buffer. If you cannot find
- * the file, create a new buffer, read in the
- * text, and switch to the new buffer.
- */
- filevisit(f, n, k)
- {
- register BUFFER *bp;
- register WINDOW *wp;
- register LINE *lp;
- register int i;
- register int s;
- char bname[NBUFN];
- char fname[NFILEN];
-
- if ((s=ereply("Visit file: ", fname, NFILEN)) != TRUE)
- return (s);
- adjustcase(fname);
- for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
- if (strcmp(bp->b_fname, fname) == 0) {
- if (--curbp->b_nwnd == 0) {
- curbp->b_dotp = curwp->w_dotp;
- curbp->b_doto = curwp->w_doto;
- curbp->b_markp = curwp->w_markp;
- curbp->b_marko = curwp->w_marko;
- }
- curbp = bp;
- curwp->w_bufp = bp;
- if (bp->b_nwnd++ == 0) {
- curwp->w_dotp = bp->b_dotp;
- curwp->w_doto = bp->b_doto;
- curwp->w_markp = bp->b_markp;
- curwp->w_marko = bp->b_marko;
- } else {
- wp = wheadp;
- while (wp != NULL) {
- if (wp!=curwp && wp->w_bufp==bp) {
- curwp->w_dotp = wp->w_dotp;
- curwp->w_doto = wp->w_doto;
- curwp->w_markp = wp->w_markp;
- curwp->w_marko = wp->w_marko;
- break;
- }
- wp = wp->w_wndp;
- }
- }
- lp = curwp->w_dotp;
- i = curwp->w_ntrows/2;
- while (i-- && lback(lp)!=curbp->b_linep)
- lp = lback(lp);
- curwp->w_linep = lp;
- curwp->w_flag |= WFMODE|WFHARD;
- if (kbdmop == NULL)
- eprintf("[Old buffer]");
- return (TRUE);
- }
- }
- makename(bname, fname); /* New buffer name. */
- while ((bp=bfind(bname, FALSE)) != NULL) {
- s = ereply("Buffer name: ", bname, NBUFN);
- if (s == ABORT) /* ^G to just quit */
- return (s);
- if (s == FALSE) { /* CR to clobber it */
- makename(bname, fname);
- break;
- }
- }
- if (bp==NULL && (bp=bfind(bname, TRUE))==NULL) {
- eprintf("Cannot create buffer");
- return (FALSE);
- }
- if (--curbp->b_nwnd == 0) { /* Undisplay. */
- curbp->b_dotp = curwp->w_dotp;
- curbp->b_doto = curwp->w_doto;
- curbp->b_markp = curwp->w_markp;
- curbp->b_marko = curwp->w_marko;
- }
- curbp = bp; /* Switch to it. */
- curwp->w_bufp = bp;
- curbp->b_nwnd++;
- return (readin(fname)); /* Read it in. */
- }
-
- /*
- * Read the file "fname" into the current buffer.
- * Make all of the text in the buffer go away, after checking
- * for unsaved changes. This is called by the "read" command, the
- * "visit" command, and the mainline (for "uemacs file"). If the
- * BACKUP conditional is set, then this routine also does the read
- * end of backup processing. The BFBAK flag, if set in a buffer,
- * says that a backup should be taken. It is set when a file is
- * read in, but not on a new file (you don't need to make a backup
- * copy of nothing). Return a standard status. Print a summary
- * (lines read, error message) out as well.
- */
- readin(fname)
- char fname[];
- {
- register LINE *lp1;
- register LINE *lp2;
- register int i;
- register WINDOW *wp;
- register BUFFER *bp;
- register int s;
- register int nbytes;
- register int nline;
- char line[NLINE];
-
- bp = curbp; /* Cheap. */
- if ((s=bclear(bp)) != TRUE) /* Might be old. */
- return (s);
- #if BACKUP
- bp->b_flag &= ~(BFCHG|BFBAK); /* No change, backup. */
- #else
- bp->b_flag &= ~BFCHG; /* No change. */
- #endif
- strcpy(bp->b_fname, fname);
- if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
- goto out;
- if (s == FIOFNF) { /* File not found. */
- if (kbdmop == NULL)
- eprintf("[New file]");
- goto out;
- }
- nline = 0;
- while ((s=ffgetline(line, NLINE)) == FIOSUC) {
- nbytes = strlen(line);
- if ((lp1=lalloc(nbytes)) == NULL) {
- s = FIOERR; /* Keep message on the */
- break; /* display. */
- }
- lp2 = lback(curbp->b_linep);
- lp2->l_fp = lp1;
- lp1->l_fp = curbp->b_linep;
- lp1->l_bp = lp2;
- curbp->b_linep->l_bp = lp1;
- for (i=0; i<nbytes; ++i)
- lputc(lp1, i, line[i]);
- ++nline;
- }
- ffclose(); /* Ignore errors. */
- if (s==FIOEOF && kbdmop==NULL) { /* Don't zap an error. */
- if (nline == 1)
- eprintf("[Read 1 line]");
- else
- eprintf("[Read %d lines]", nline);
- }
- #if BACKUP
- curbp->b_flag |= BFBAK; /* Need a backup. */
- #endif
- out:
- for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
- if (wp->w_bufp == curbp) {
- wp->w_linep = lforw(curbp->b_linep);
- wp->w_dotp = lforw(curbp->b_linep);
- wp->w_doto = 0;
- wp->w_markp = NULL;
- wp->w_marko = 0;
- wp->w_flag |= WFMODE|WFHARD;
- }
- }
- if (s == FIOERR) /* False if error. */
- return (FALSE);
- return (TRUE);
- }
-
- /*
- * Take a file name, and from it
- * fabricate a buffer name. This routine knows
- * about the syntax of file names on the target system.
- * BDC1 left scan delimiter.
- * BDC2 optional second left scan delimiter.
- * BDC3 optional right scan delimiter.
- */
- makename(bname, fname)
- char bname[];
- char fname[];
- {
- register char *cp1;
- register char *cp2;
-
- cp1 = &fname[0];
- while (*cp1 != 0)
- ++cp1;
- #ifdef BDC2
- while (cp1!=&fname[0] && cp1[-1]!=BDC1 && cp1[-1]!=BDC2)
- --cp1;
- #else
- while (cp1!=&fname[0] && cp1[-1]!=BDC1)
- --cp1;
- #endif
- cp2 = &bname[0];
- #ifdef BDC3
- while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=BDC3)
- *cp2++ = *cp1++;
- #else
- while (cp2!=&bname[NBUFN-1] && *cp1!=0)
- *cp2++ = *cp1++;
- #endif
- *cp2 = 0;
- }
-
- /*
- * Ask for a file name, and write the
- * contents of the current buffer to that file.
- * Update the remembered file name and clear the
- * buffer changed flag. This handling of file names
- * is different from the earlier versions, and
- * is more compatable with Gosling EMACS than
- * with ITS EMACS.
- */
- filewrite(f, n, k)
- {
- register WINDOW *wp;
- register int s;
- char fname[NFILEN];
-
- if ((s=ereply("Write file: ", fname, NFILEN)) != TRUE)
- return (s);
- adjustcase(fname);
- if ((s=writeout(fname)) == TRUE) {
- strcpy(curbp->b_fname, fname);
- curbp->b_flag &= ~BFCHG;
- wp = wheadp; /* Update mode lines. */
- while (wp != NULL) {
- if (wp->w_bufp == curbp)
- wp->w_flag |= WFMODE;
- wp = wp->w_wndp;
- }
- }
- #if BACKUP
- curbp->b_flag &= ~BFBAK; /* No backup. */
- #endif
- return (s);
- }
-
- /*
- * Save the contents of the current buffer back into
- * its associated file. Do nothing if there have been no changes
- * (is this a bug, or a feature). Error if there is no remembered
- * file name. If this is the first write since the read or visit,
- * then a backup copy of the file is made.
- */
- filesave(f, n, k)
- {
- register WINDOW *wp;
- register int s;
-
- if ((curbp->b_flag&BFCHG) == 0) /* Return, no changes. */
- return (TRUE);
- if (curbp->b_fname[0] == 0) { /* Must have a name. */
- eprintf("No file name");
- return (FALSE);
- }
- #if BACKUP
- if ((curbp->b_flag&BFBAK) != 0) {
- s = fbackupfile(curbp->b_fname);
- if (s == ABORT) /* Hard error. */
- return (s);
- if (s == FALSE /* Softer error. */
- && (s=eyesno("Backup error, save anyway")) != TRUE)
- return (s);
- }
- #endif
- if ((s=writeout(curbp->b_fname)) == TRUE) {
- curbp->b_flag &= ~BFCHG;
- wp = wheadp; /* Update mode lines. */
- while (wp != NULL) {
- if (wp->w_bufp == curbp)
- wp->w_flag |= WFMODE;
- wp = wp->w_wndp;
- }
- }
- #if BACKUP
- curbp->b_flag &= ~BFBAK; /* No backup. */
- #endif
- return (s);
- }
-
- /*
- * This function performs the details of file
- * writing. Uses the file management routines in the
- * "fileio.c" package. The number of lines written is
- * displayed. Sadly, it looks inside a LINE; provide
- * a macro for this. Most of the grief is error
- * checking of some sort.
- */
- writeout(fn)
- char *fn;
- {
- register int s;
- register LINE *lp;
- register int nline;
-
- if ((s=ffwopen(fn)) != FIOSUC) /* Open writes message. */
- return (FALSE);
- lp = lforw(curbp->b_linep); /* First line. */
- nline = 0; /* Number of lines. */
- while (lp != curbp->b_linep) {
- if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
- break;
- ++nline;
- lp = lforw(lp);
- }
- if (s == FIOSUC) { /* No write error. */
- s = ffclose();
- if (s==FIOSUC && kbdmop==NULL) {
- if (nline == 1)
- eprintf("[Wrote 1 line]");
- else
- eprintf("[Wrote %d lines]", nline);
- }
- } else /* Ignore close error */
- ffclose(); /* if a write error. */
- if (s != FIOSUC) /* Some sort of error. */
- return (FALSE);
- return (TRUE);
- }
-
- /*
- * The command allows the user
- * to modify the file name associated with
- * the current buffer. It is like the "f" command
- * in UNIX "ed". The operation is simple; just zap
- * the name in the BUFFER structure, and mark the windows
- * as needing an update. You can type a blank line at the
- * prompt if you wish.
- */
- filename(f, n, k)
- {
- register WINDOW *wp;
- register int s;
- char fname[NFILEN];
-
- if ((s=ereply("Name: ", fname, NFILEN)) == ABORT)
- return (s);
- adjustcase(fname);
- strcpy(curbp->b_fname, fname); /* Fix name. */
- wp = wheadp; /* Update mode lines. */
- while (wp != NULL) {
- if (wp->w_bufp == curbp)
- wp->w_flag |= WFMODE;
- wp = wp->w_wndp;
- }
- #if BACKUP
- curbp->b_flag &= ~BFBAK; /* No backup. */
- #endif
- return (TRUE);
- }
- SHAR_EOF
- if test 9404 -ne "`wc -c < 'file.c'`"
- then
- echo shar: error transmitting "'file.c'" '(should have been 9404 characters)'
- fi
- fi
- echo shar: extracting "'kbd.c'" '(2689 characters)'
- if test -f 'kbd.c'
- then
- echo shar: will not over-write existing file "'kbd.c'"
- else
- cat << \SHAR_EOF > 'kbd.c'
- /*
- * Name: MicroEMACS
- * Terminal independent keyboard handling.
- * Version: 29
- * Last edit: 05-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- */
- #include "def.h"
-
- /*
- * Read in a key, doing the terminal
- * independent prefix handling. The terminal specific
- * "getkbd" routine gets the first swing, and may return
- * one of the special codes used by the special keys
- * on the keyboard. The "getkbd" routine returns the
- * C0 controls as received; this routine moves them to
- * the right spot in 11 bit code.
- */
- getkey()
- {
- register int c;
-
- c = getkbd();
- if (c == METACH) /* M- */
- c = KMETA | getctl();
- else if (c == CTRLCH) /* C- */
- c = KCTRL | getctl();
- else if (c == CTMECH) /* C-M- */
- c = KCTRL | KMETA | getctl();
- else if (c>=0x00 && c<=0x1F) /* Relocate control. */
- c = KCTRL | (c+'@');
- if (c == (KCTRL|'X')) /* C-X */
- c = KCTLX | getctl();
- return (c);
- }
-
- /*
- * Used above.
- */
- getctl()
- {
- register int c;
-
- c = ttgetc();
- if (ISLOWER(c) != FALSE)
- c = TOUPPER(c);
- if (c>=0x00 && c<=0x1F) /* Relocate control. */
- c = KCTRL | (c+'@');
- return (c);
- }
-
- /*
- * Transform a key code into a name,
- * using a table for the special keys and combination
- * of some hard code and some general processing for
- * the rest. None of this code is terminal specific any
- * more. This makes adding keys easier.
- */
- keyname(cp, k)
- register char *cp;
- register int k;
- {
- register char *np;
- char nbuf[3];
-
- static char hex[] = {
- '0', '1', '2', '3',
- '4', '5', '6', '7',
- '8', '9', 'A', 'B',
- 'C', 'D', 'E', 'F'
- };
-
- if ((k&KCTLX) != 0) { /* C-X prefix. */
- *cp++ = 'C';
- *cp++ = '-';
- *cp++ = 'X';
- *cp++ = ' ';
- k &= ~KCTLX;
- }
- if ((k&KCHAR)>=KFIRST && (k&KCHAR)<=KLAST) {
- if ((np=keystrings[(k&KCHAR)-KFIRST]) != NULL) {
- if ((k&KCTRL) != 0) {
- *cp++ = 'C';
- *cp++ = '-';
- }
- if ((k&KMETA) != 0) {
- *cp++ = 'M';
- *cp++ = '-';
- }
- strcpy(cp, np);
- return;
- }
- }
- if ((k&~KMETA) == (KCTRL|'I')) /* Some specials. */
- np = "Tab";
- else if ((k&~KMETA) == (KCTRL|'M'))
- np = "Return";
- else if ((k&~KMETA) == (KCTRL|'H'))
- np = "Backspace";
- else if ((k&~KMETA) == ' ')
- np = "Space";
- else if ((k&~KMETA) == 0x7F)
- np = "Rubout";
- else {
- if ((k&KCTRL) != 0) { /* Add C- mark. */
- *cp++ = 'C';
- *cp++ = '-';
- }
- np = &nbuf[0];
- if (((k&KCHAR)>=0x20 && (k&KCHAR)<=0x7E)
- || ((k&KCHAR)>=0xA0 && (k&KCHAR)<=0xFE)) {
- nbuf[0] = k&KCHAR; /* Graphic. */
- nbuf[1] = 0;
- } else { /* Non graphic. */
- nbuf[0] = hex[(k>>4)&0x0F];
- nbuf[1] = hex[k&0x0F];
- nbuf[2] = 0;
- }
- }
- if ((k&KMETA) != 0) { /* Add M- mark. */
- *cp++ = 'M';
- *cp++ = '-';
- }
- strcpy(cp, np);
- }
- SHAR_EOF
- if test 2689 -ne "`wc -c < 'kbd.c'`"
- then
- echo shar: error transmitting "'kbd.c'" '(should have been 2689 characters)'
- fi
- fi
- echo shar: extracting "'line.c'" '(14554 characters)'
- if test -f 'line.c'
- then
- echo shar: will not over-write existing file "'line.c'"
- else
- cat << \SHAR_EOF > 'line.c'
- /*
- * Name: MicroEMACS
- * Text line handling.
- * Version: 29
- * Last edit: 14-Feb-86
- * By: rex::conroy, vox::ellison
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- * ...!dec-vox!ellison
- *
- * The functions in this file
- * are a general set of line management
- * utilities. They are the only routines that
- * touch the text. They also touch the buffer
- * and window structures, to make sure that the
- * necessary updating gets done. There are routines
- * in this file that handle the kill buffer too.
- * It isn't here for any good reason.
- *
- * Note that this code only updates the dot and
- * mark values in the window list. Since all the code
- * acts on the current window, the buffer that we
- * are editing must be being displayed, which means
- * that "b_nwnd" is non zero, which means that the
- * dot and mark values in the buffer headers are
- * nonsense.
- */
- #include "def.h"
-
- #define NBLOCK 16 /* Line block chunk size */
-
- #ifndef KBLOCK
- #define KBLOCK 256 /* Kill buffer block size. */
- #endif
-
- char *kbufp = NULL; /* Kill buffer data. */
- int kused = 0; /* # of bytes used in KB. */
- int ksize = 0; /* # of bytes allocated in KB. */
-
- /*
- * This routine allocates a block
- * of memory large enough to hold a LINE
- * containing "used" characters. The block is
- * always rounded up a bit. Return a pointer
- * to the new block, or NULL if there isn't
- * any memory left. Print a message in the
- * message line if no space.
- */
- LINE *
- lalloc(used)
- register int used;
- {
- register LINE *lp;
- register int size;
-
- size = (used+NBLOCK-1) & ~(NBLOCK-1);
- if (size == 0) /* Assume that an empty */
- size = NBLOCK; /* line is for type-in. */
- if ((lp=(LINE *)malloc(sizeof(LINE)+size)) == NULL) {
- eprintf("Cannot allocate %d bytes", size);
- return (NULL);
- }
- lp->l_size = size;
- lp->l_used = used;
- return (lp);
- }
-
- /*
- * Delete line "lp". Fix all of the
- * links that might point at it (they are
- * moved to offset 0 of the next line.
- * Unlink the line from whatever buffer it
- * might be in. Release the memory. The
- * buffers are updated too; the magic conditions
- * described in the above comments don't hold
- * here.
- */
- lfree(lp)
- register LINE *lp;
- {
- register BUFFER *bp;
- register WINDOW *wp;
-
- wp = wheadp;
- while (wp != NULL) {
- if (wp->w_linep == lp)
- wp->w_linep = lp->l_fp;
- if (wp->w_dotp == lp) {
- wp->w_dotp = lp->l_fp;
- wp->w_doto = 0;
- }
- if (wp->w_markp == lp) {
- wp->w_markp = lp->l_fp;
- wp->w_marko = 0;
- }
- wp = wp->w_wndp;
- }
- bp = bheadp;
- while (bp != NULL) {
- if (bp->b_nwnd == 0) {
- if (bp->b_dotp == lp) {
- bp->b_dotp = lp->l_fp;
- bp->b_doto = 0;
- }
- if (bp->b_markp == lp) {
- bp->b_markp = lp->l_fp;
- bp->b_marko = 0;
- }
- }
- bp = bp->b_bufp;
- }
- lp->l_bp->l_fp = lp->l_fp;
- lp->l_fp->l_bp = lp->l_bp;
- free((char *) lp);
- }
-
- /*
- * This routine gets called when
- * a character is changed in place in the
- * current buffer. It updates all of the required
- * flags in the buffer and window system. The flag
- * used is passed as an argument; if the buffer is being
- * displayed in more than 1 window we change EDIT to
- * HARD. Set MODE if the mode line needs to be
- * updated (the "*" has to be set).
- */
- lchange(flag)
- register int flag;
- {
- register WINDOW *wp;
-
- if (curbp->b_nwnd != 1) /* Ensure hard. */
- flag = WFHARD;
- if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
- flag |= WFMODE; /* update mode lines. */
- curbp->b_flag |= BFCHG;
- }
- wp = wheadp;
- while (wp != NULL) {
- if (wp->w_bufp == curbp)
- wp->w_flag |= flag;
- wp = wp->w_wndp;
- }
- }
-
- /*
- * Insert "n" copies of the character "c"
- * at the current location of dot. In the easy case
- * all that happens is the text is stored in the line.
- * In the hard case, the line has to be reallocated.
- * When the window list is updated, take special
- * care; I screwed it up once. You always update dot
- * in the current window. You update mark, and a
- * dot in another window, if it is greater than
- * the place where you did the insert. Return TRUE
- * if all is well, and FALSE on errors.
- */
- linsert(n, c)
- {
- register char *cp1;
- register char *cp2;
- register LINE *lp1;
- register LINE *lp2;
- register LINE *lp3;
- register int doto;
- register int i;
- register WINDOW *wp;
-
- lchange(WFEDIT);
- lp1 = curwp->w_dotp; /* Current line */
- if (lp1 == curbp->b_linep) { /* At the end: special */
- if (curwp->w_doto != 0) {
- eprintf("bug: linsert");
- return (FALSE);
- }
- if ((lp2=lalloc(n)) == NULL) /* Allocate new line */
- return (FALSE);
- lp3 = lp1->l_bp; /* Previous line */
- lp3->l_fp = lp2; /* Link in */
- lp2->l_fp = lp1;
- lp1->l_bp = lp2;
- lp2->l_bp = lp3;
- for (i=0; i<n; ++i)
- lp2->l_text[i] = c;
- curwp->w_dotp = lp2;
- curwp->w_doto = n;
- return (TRUE);
- }
- doto = curwp->w_doto; /* Save for later. */
- if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */
- if ((lp2=lalloc(lp1->l_used+n)) == NULL)
- return (FALSE);
- cp1 = &lp1->l_text[0];
- cp2 = &lp2->l_text[0];
- while (cp1 != &lp1->l_text[doto])
- *cp2++ = *cp1++;
- cp2 += n;
- while (cp1 != &lp1->l_text[lp1->l_used])
- *cp2++ = *cp1++;
- lp1->l_bp->l_fp = lp2;
- lp2->l_fp = lp1->l_fp;
- lp1->l_fp->l_bp = lp2;
- lp2->l_bp = lp1->l_bp;
- free((char *) lp1);
- } else { /* Easy: in place */
- lp2 = lp1; /* Pretend new line */
- lp2->l_used += n;
- cp2 = &lp1->l_text[lp1->l_used];
- cp1 = cp2-n;
- while (cp1 != &lp1->l_text[doto])
- *--cp2 = *--cp1;
- }
- for (i=0; i<n; ++i) /* Add the characters */
- lp2->l_text[doto+i] = c;
- wp = wheadp; /* Update windows */
- while (wp != NULL) {
- if (wp->w_linep == lp1)
- wp->w_linep = lp2;
- if (wp->w_dotp == lp1) {
- wp->w_dotp = lp2;
- if (wp==curwp || wp->w_doto>doto)
- wp->w_doto += n;
- }
- if (wp->w_markp == lp1) {
- wp->w_markp = lp2;
- if (wp->w_marko > doto)
- wp->w_marko += n;
- }
- wp = wp->w_wndp;
- }
- return (TRUE);
- }
-
- /*
- * Insert a newline into the buffer
- * at the current location of dot in the current
- * window. The funny ass-backwards way it does things
- * is not a botch; it just makes the last line in
- * the file not a special case. Return TRUE if everything
- * works out and FALSE on error (memory allocation
- * failure). The update of dot and mark is a bit
- * easier then in the above case, because the split
- * forces more updating.
- */
- lnewline()
- {
- register char *cp1;
- register char *cp2;
- register LINE *lp1;
- register LINE *lp2;
- register int doto;
- register WINDOW *wp;
-
- lchange(WFHARD);
- lp1 = curwp->w_dotp; /* Get the address and */
- doto = curwp->w_doto; /* offset of "." */
- if ((lp2=lalloc(doto)) == NULL) /* New first half line */
- return (FALSE);
- cp1 = &lp1->l_text[0]; /* Shuffle text around */
- cp2 = &lp2->l_text[0];
- while (cp1 != &lp1->l_text[doto])
- *cp2++ = *cp1++;
- cp2 = &lp1->l_text[0];
- while (cp1 != &lp1->l_text[lp1->l_used])
- *cp2++ = *cp1++;
- lp1->l_used -= doto;
- lp2->l_bp = lp1->l_bp;
- lp1->l_bp = lp2;
- lp2->l_bp->l_fp = lp2;
- lp2->l_fp = lp1;
- wp = wheadp; /* Windows */
- while (wp != NULL) {
- if (wp->w_linep == lp1)
- wp->w_linep = lp2;
- if (wp->w_dotp == lp1) {
- if (wp->w_doto < doto)
- wp->w_dotp = lp2;
- else
- wp->w_doto -= doto;
- }
- if (wp->w_markp == lp1) {
- if (wp->w_marko < doto)
- wp->w_markp = lp2;
- else
- wp->w_marko -= doto;
- }
- wp = wp->w_wndp;
- }
- return (TRUE);
- }
-
- /*
- * This function deletes "n" bytes,
- * starting at dot. It understands how do deal
- * with end of lines, etc. It returns TRUE if all
- * of the characters were deleted, and FALSE if
- * they were not (because dot ran into the end of
- * the buffer. The "kflag" is TRUE if the text
- * should be put in the kill buffer.
- */
- ldelete(n, kflag)
- {
- register char *cp1;
- register char *cp2;
- register LINE *dotp;
- register int doto;
- register int chunk;
- register WINDOW *wp;
-
- while (n != 0) {
- dotp = curwp->w_dotp;
- doto = curwp->w_doto;
- if (dotp == curbp->b_linep) /* Hit end of buffer. */
- return (FALSE);
- chunk = dotp->l_used-doto; /* Size of chunk. */
- if (chunk > n)
- chunk = n;
- if (chunk == 0) { /* End of line, merge. */
- lchange(WFHARD);
- if (ldelnewline() == FALSE
- || (kflag!=FALSE && kinsert('\n')==FALSE))
- return (FALSE);
- --n;
- continue;
- }
- lchange(WFEDIT);
- cp1 = &dotp->l_text[doto]; /* Scrunch text. */
- cp2 = cp1 + chunk;
- if (kflag != FALSE) { /* Kill? */
- while (cp1 != cp2) {
- if (kinsert(*cp1) == FALSE)
- return (FALSE);
- ++cp1;
- }
- cp1 = &dotp->l_text[doto];
- }
- while (cp2 != &dotp->l_text[dotp->l_used])
- *cp1++ = *cp2++;
- dotp->l_used -= chunk;
- wp = wheadp; /* Fix windows */
- while (wp != NULL) {
- if (wp->w_dotp==dotp && wp->w_doto>=doto) {
- wp->w_doto -= chunk;
- if (wp->w_doto < doto)
- wp->w_doto = doto;
- }
- if (wp->w_markp==dotp && wp->w_marko>=doto) {
- wp->w_marko -= chunk;
- if (wp->w_marko < doto)
- wp->w_marko = doto;
- }
- wp = wp->w_wndp;
- }
- n -= chunk;
- }
- return (TRUE);
- }
-
- /*
- * Delete a newline. Join the current line
- * with the next line. If the next line is the magic
- * header line always return TRUE; merging the last line
- * with the header line can be thought of as always being a
- * successful operation, even if nothing is done, and this makes
- * the kill buffer work "right". Easy cases can be done by
- * shuffling data around. Hard cases require that lines be moved
- * about in memory. Return FALSE on error and TRUE if all
- * looks ok. Called by "ldelete" only.
- */
- ldelnewline()
- {
- register char *cp1;
- register char *cp2;
- register LINE *lp1;
- register LINE *lp2;
- register LINE *lp3;
- register WINDOW *wp;
-
- lp1 = curwp->w_dotp;
- lp2 = lp1->l_fp;
- if (lp2 == curbp->b_linep) { /* At the buffer end. */
- if (lp1->l_used == 0) /* Blank line. */
- lfree(lp1);
- return (TRUE);
- }
- if (lp2->l_used <= lp1->l_size-lp1->l_used) {
- cp1 = &lp1->l_text[lp1->l_used];
- cp2 = &lp2->l_text[0];
- while (cp2 != &lp2->l_text[lp2->l_used])
- *cp1++ = *cp2++;
- wp = wheadp;
- while (wp != NULL) {
- if (wp->w_linep == lp2)
- wp->w_linep = lp1;
- if (wp->w_dotp == lp2) {
- wp->w_dotp = lp1;
- wp->w_doto += lp1->l_used;
- }
- if (wp->w_markp == lp2) {
- wp->w_markp = lp1;
- wp->w_marko += lp1->l_used;
- }
- wp = wp->w_wndp;
- }
- lp1->l_used += lp2->l_used;
- lp1->l_fp = lp2->l_fp;
- lp2->l_fp->l_bp = lp1;
- free((char *) lp2);
- return (TRUE);
- }
- if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
- return (FALSE);
- cp1 = &lp1->l_text[0];
- cp2 = &lp3->l_text[0];
- while (cp1 != &lp1->l_text[lp1->l_used])
- *cp2++ = *cp1++;
- cp1 = &lp2->l_text[0];
- while (cp1 != &lp2->l_text[lp2->l_used])
- *cp2++ = *cp1++;
- lp1->l_bp->l_fp = lp3;
- lp3->l_fp = lp2->l_fp;
- lp2->l_fp->l_bp = lp3;
- lp3->l_bp = lp1->l_bp;
- wp = wheadp;
- while (wp != NULL) {
- if (wp->w_linep==lp1 || wp->w_linep==lp2)
- wp->w_linep = lp3;
- if (wp->w_dotp == lp1)
- wp->w_dotp = lp3;
- else if (wp->w_dotp == lp2) {
- wp->w_dotp = lp3;
- wp->w_doto += lp1->l_used;
- }
- if (wp->w_markp == lp1)
- wp->w_markp = lp3;
- else if (wp->w_markp == lp2) {
- wp->w_markp = lp3;
- wp->w_marko += lp1->l_used;
- }
- wp = wp->w_wndp;
- }
- free((char *) lp1);
- free((char *) lp2);
- return (TRUE);
- }
-
- /*
- * Replace plen characters before dot with argument string.
- * Control-J characters in st are interpreted as newlines.
- * There is a casehack disable flag (normally it likes to match
- * case of replacement to what was there).
- */
- lreplace(plen, st, f)
- register int plen; /* length to remove */
- char *st; /* replacement string */
- int f; /* case hack disable */
- {
- register int rlen; /* replacement length */
- register int rtype; /* capitalization */
- register int c; /* used for random characters */
- register int doto; /* offset into line */
-
- /*
- * Find the capitalization of the word that was found.
- * f says use exact case of replacement string (same thing that
- * happens with lowercase found), so bypass check.
- */
- backchar(TRUE, plen, KRANDOM);
- rtype = _L;
- c = lgetc(curwp->w_dotp, curwp->w_doto);
- if (ISUPPER(c)!=FALSE && f==FALSE) {
- rtype = _U|_L;
- if (curwp->w_doto+1 < llength(curwp->w_dotp)) {
- c = lgetc(curwp->w_dotp, curwp->w_doto+1);
- if (ISUPPER(c) != FALSE) {
- rtype = _U;
- }
- }
- }
-
- /*
- * make the string lengths match (either pad the line
- * so that it will fit, or scrunch out the excess).
- * be careful with dot's offset.
- */
- rlen = strlen(st);
- doto = curwp->w_doto;
- if (plen > rlen)
- ldelete(plen-rlen, FALSE);
- else if (plen < rlen) {
- if (linsert(rlen-plen, ' ') == FALSE)
- return (FALSE);
- }
- curwp->w_doto = doto;
-
- /*
- * do the replacement: If was capital, then place first
- * char as if upper, and subsequent chars as if lower.
- * If inserting upper, check replacement for case.
- */
- while ((c = *st++&0xff) != '\0') {
- if ((rtype&_U)!=0 && ISLOWER(c)!=0)
- c = TOUPPER(c);
- if (rtype == (_U|_L))
- rtype = _L;
- if (c == '\n') {
- if (curwp->w_doto == llength(curwp->w_dotp))
- forwchar(FALSE, 1, KRANDOM);
- else {
- ldelete(1, FALSE);
- lnewline();
- }
- } else if (curwp->w_dotp == curbp->b_linep) {
- linsert(1, c);
- } else if (curwp->w_doto == llength(curwp->w_dotp)) {
- ldelete(1, FALSE);
- linsert(1, c);
- } else
- lputc(curwp->w_dotp, curwp->w_doto++, c);
- }
- lchange(WFHARD);
- return (TRUE);
- }
-
- /*
- * Delete all of the text
- * saved in the kill buffer. Called by commands
- * when a new kill context is being created. The kill
- * buffer array is released, just in case the buffer has
- * grown to immense size. No errors.
- */
- kdelete()
- {
- if (kbufp != NULL) {
- free((char *) kbufp);
- kbufp = NULL;
- kused = 0;
- ksize = 0;
- }
- }
-
- /*
- * Insert a character to the kill buffer,
- * enlarging the buffer if there isn't any room. Always
- * grow the buffer in chunks, on the assumption that if you
- * put something in the kill buffer you are going to put
- * more stuff there too later. Return TRUE if all is
- * well, and FALSE on errors. Print a message on
- * errors.
- */
- kinsert(c)
- {
- register char *nbufp;
- register int i;
-
- if (kused == ksize) {
- if ((nbufp=malloc(ksize+KBLOCK)) == NULL) {
- eprintf("Too many kills");
- return (FALSE);
- }
- for (i=0; i<ksize; ++i)
- nbufp[i] = kbufp[i];
- if (kbufp != NULL)
- free((char *) kbufp);
- kbufp = nbufp;
- ksize += KBLOCK;
- }
- kbufp[kused++] = c;
- return (TRUE);
- }
-
- /*
- * This function gets characters from
- * the kill buffer. If the character index "n" is
- * off the end, it returns "-1". This lets the caller
- * just scan along until it gets a "-1" back.
- */
- kremove(n)
- {
- if (n >= kused)
- return (-1);
- return (kbufp[n] & 0xFF);
- }
- SHAR_EOF
- if test 14554 -ne "`wc -c < 'line.c'`"
- then
- echo shar: error transmitting "'line.c'" '(should have been 14554 characters)'
- fi
- fi
- echo shar: extracting "'main.c'" '(6208 characters)'
- if test -f 'main.c'
- then
- echo shar: will not over-write existing file "'main.c'"
- else
- cat << \SHAR_EOF > 'main.c'
- /*
- * Name: MicroEMACS
- * Mainline, macro commands.
- * Version: 29
- * Last edit: 05-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- */
- #include "def.h"
-
- int thisflag; /* Flags, this command */
- int lastflag; /* Flags, last command */
- int curgoal; /* Goal column */
- BUFFER *curbp; /* Current buffer */
- WINDOW *curwp; /* Current window */
- BUFFER *bheadp; /* BUFFER listhead */
- WINDOW *wheadp; /* WINDOW listhead */
- BUFFER *blistp; /* Buffer list BUFFER */
- short kbdm[NKBDM] = (KCTLX|')'); /* Macro */
- short *kbdmip; /* Input for above */
- short *kbdmop; /* Output for above */
- char pat[NPAT]; /* Pattern */
- SYMBOL *symbol[NSHASH]; /* Symbol table listhead. */
- SYMBOL *binding[NKEYS]; /* Key bindings. */
-
- main(argc, argv)
- char *argv[];
- {
- register int c;
- register int f;
- register int n;
- register int mflag;
- char bname[NBUFN];
-
- strcpy(bname, "main"); /* Get buffer name. */
- if (argc > 1)
- makename(bname, argv[1]);
- vtinit(); /* Virtual terminal. */
- edinit(bname); /* Buffers, windows. */
- keymapinit(); /* Symbols, bindings. */
- if (argc > 1) {
- update();
- readin(argv[1]);
- }
- lastflag = 0; /* Fake last flags. */
- loop:
- update(); /* Fix up the screen. */
- c = getkey();
- if (epresf != FALSE) {
- eerase();
- update();
- }
- f = FALSE;
- n = 1;
- if (c == (KCTRL|'U')) { /* ^U, start argument. */
- f = TRUE;
- n = 4;
- while ((c=getkey()) == (KCTRL|'U'))
- n *= 4;
- if ((c>='0' && c<='9') || c=='-') {
- if (c == '-') {
- n = 0;
- mflag = TRUE;
- } else {
- n = c - '0';
- mflag = FALSE;
- }
- while ((c=getkey())>='0' && c<='9')
- n = 10*n + c - '0';
- if (mflag != FALSE)
- n = -n;
- }
- }
- if (kbdmip != NULL) { /* Save macro strokes. */
- if (c!=(KCTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
- ctrlg(FALSE, 0, KRANDOM);
- goto loop;
- }
- if (f != FALSE) {
- *kbdmip++ = (KCTRL|'U');
- *kbdmip++ = n;
- }
- *kbdmip++ = c;
- }
- execute(c, f, n); /* Do it. */
- goto loop;
- }
-
- /*
- * Command execution. Look up the binding in the the
- * binding array, and do what it says. Return a very bad status
- * if there is no binding, or if the symbol has a type that
- * is not usable (there is no way to get this into a symbol table
- * entry now). Also fiddle with the flags.
- */
- execute(c, f, n)
- {
- register SYMBOL *sp;
- register int status;
-
- if ((sp=binding[c]) != NULL) {
- thisflag = 0;
- status = (*sp->s_funcp)(f, n, c);
- lastflag = thisflag;
- return (status);
- }
- lastflag = 0;
- return (ABORT);
- }
-
- /*
- * Initialize all of the buffers
- * and windows. The buffer name is passed down as
- * an argument, because the main routine may have been
- * told to read in a file by default, and we want the
- * buffer name to be right.
- */
- edinit(bname)
- char bname[];
- {
- register BUFFER *bp;
- register WINDOW *wp;
-
- bp = bfind(bname, TRUE); /* Text buffer. */
- blistp = bcreate(""); /* Special list buffer. */
- wp = (WINDOW *) malloc(sizeof(WINDOW)); /* Initial window. */
- if (bp==NULL || wp==NULL || blistp==NULL)
- abort();
- curbp = bp; /* Current ones. */
- wheadp = wp;
- curwp = wp;
- wp->w_wndp = NULL; /* Initialize window. */
- wp->w_bufp = bp;
- bp->b_nwnd = 1; /* Displayed. */
- wp->w_linep = bp->b_linep;
- wp->w_dotp = bp->b_linep;
- wp->w_doto = 0;
- wp->w_markp = NULL;
- wp->w_marko = 0;
- wp->w_toprow = 0;
- wp->w_ntrows = nrow-2; /* 2 = mode, echo. */
- wp->w_force = 0;
- wp->w_flag = WFMODE|WFHARD; /* Full. */
- }
-
- /*
- * Fancy quit command, as implemented
- * by Jeff. If the current buffer has changed
- * do a write current buffer. Otherwise run a command
- * interpreter in a subjob. Two of these will get you
- * out. Bound to "C-Z".
- */
- jeffexit(f, n, k)
- {
- if ((curbp->b_flag&BFCHG) != 0) /* Changed. */
- return (filesave(f, n, KRANDOM));
- return (spawncli(f, n, KRANDOM)); /* Suspend. */
- }
-
- /*
- * Quit command. If an argument, always
- * quit. Otherwise confirm if a buffer has been
- * changed and not written out. Normally bound
- * to "C-X C-C".
- */
- quit(f, n, k)
- {
- register int s;
-
- if (f != FALSE /* Argument forces it. */
- || anycb() == FALSE /* All buffers clean. */
- || (s=eyesno("Quit")) == TRUE) { /* User says it's OK. */
- vttidy();
- exit(GOOD);
- }
- return (s);
- }
-
- /*
- * Begin a keyboard macro.
- * Error if not at the top level
- * in keyboard processing. Set up
- * variables and return.
- */
- ctlxlp(f, n, k)
- {
- if (kbdmip!=NULL || kbdmop!=NULL) {
- eprintf("Not now");
- return (FALSE);
- }
- eprintf("[Start macro]");
- kbdmip = &kbdm[0];
- return (TRUE);
- }
-
- /*
- * End keyboard macro. Check for
- * the same limit conditions as the
- * above routine. Set up the variables
- * and return to the caller.
- */
- ctlxrp(f, n, k)
- {
- if (kbdmip == NULL) {
- eprintf("Not now");
- return (FALSE);
- }
- eprintf("[End macro]");
- kbdmip = NULL;
- return (TRUE);
- }
-
- /*
- * Execute a macro.
- * The command argument is the
- * number of times to loop. Quit as
- * soon as a command gets an error.
- * Return TRUE if all ok, else
- * FALSE.
- */
- ctlxe(f, n, k)
- {
- register int c;
- register int af;
- register int an;
- register int s;
-
- if (kbdmip!=NULL || kbdmop!=NULL) {
- eprintf("Not now");
- return (FALSE);
- }
- if (n <= 0)
- return (TRUE);
- do {
- kbdmop = &kbdm[0];
- do {
- af = FALSE;
- an = 1;
- if ((c = *kbdmop++) == (KCTRL|'U')) {
- af = TRUE;
- an = *kbdmop++;
- c = *kbdmop++;
- }
- s = TRUE;
- } while (c!=(KCTLX|')') && (s=execute(c, af, an))==TRUE);
- kbdmop = NULL;
- } while (s==TRUE && --n);
- return (s);
- }
-
- /*
- * Abort.
- * Beep the beeper.
- * Kill off any keyboard macro,
- * etc., that is in progress.
- * Sometimes called as a routine,
- * to do general aborting of
- * stuff.
- */
- ctrlg(f, n, k)
- {
- ttbeep();
- if (kbdmip != NULL) {
- kbdm[0] = (KCTLX|')');
- kbdmip = NULL;
- }
- return (ABORT);
- }
-
- /*
- * Display the version. All this does
- * is copy the text in the external "version" array into
- * the message system, and call the message reading code.
- * Don't call display if there is an argument.
- */
- showversion(f, n, k)
- {
- register char **cpp;
- register char *cp;
-
- cpp = &version[0];
- while ((cp = *cpp++) != NULL) {
- if (writemsg(cp) == FALSE)
- return (FALSE);
- }
- if (f != FALSE) /* No display if arg. */
- return (TRUE);
- return (readmsg());
- }
- SHAR_EOF
- if test 6208 -ne "`wc -c < 'main.c'`"
- then
- echo shar: error transmitting "'main.c'" '(should have been 6208 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-